#include "Header.h"

#define ADMIN 1
#define RES 2
#define EXIT 3

typedef struct user // 用户信息结构体
{
    int cid;
    char name[16];
} user_t;

user_t client_ids[20] = {0}; // 客户端数组

int number = 0; // 在线人数
int flg = 0;    // 私聊标志,置1为私聊

void mass_send(char *sendbuf) // 转发给所有人
{
    int i;
    for (i = 0; i < 20; i++)
    {
        if (client_ids[i].cid > 0)
        {
            send(client_ids[i].cid, sendbuf, strlen(sendbuf), 0); // 发送包装好的的信息
        }
    }
    // 记录聊天记录
    int fd = open("chat.txt", O_RDWR | O_CREAT | O_APPEND, 0666); // 创建追加写
    write(fd, sendbuf, strlen(sendbuf));
    close(fd);
}

void user_add(int cid, char *name) // 添加用户名字
{
    int i;
    for (i = 0; i < 20; i++)
    {
        if (client_ids[i].cid == cid)
        {
            strcpy(client_ids[i].name, name); // 添加名字
            printf("加入数组：%d %s\n", client_ids[i].cid, client_ids[i].name);
            break;
        }
    }
}

// 子线程
void *pthread_func(void *arg)
{
    number++;
    printf("在线人数:%d\n", number);

    // 取出cid
    int client_id = *(int *)arg;

    // 定义接收和发送缓存
    char sendbuf[256] = {0};
    char recvbuf[256] = {0};

    // 读取客户端发来的名字
    recv(client_id, recvbuf, sizeof(recvbuf), 0);

    char name[16] = {0};
    strcpy(name, recvbuf);

    // 把用户数据存入结构体数组中，方便管理
    user_add(client_id, name);
    printf("%s上线了\n", name);
    puts("");

    // 发送加入群聊
    char hint[256] = {0};
    strcpy(hint, name);
    strcat(hint, "加入了聊天室,");
    strcat(hint, "当前在线用户：");
    int n;
    for (n = 0; n < number; n++)
    {
        strcat(hint, client_ids[n].name); // 添加名字
        strcat(hint, " ");
    }
    strcat(hint, "\n");
    mass_send(hint);

    // 添加消息头（名字：）
    char namehead[256] = {0};
    strcpy(namehead, name);
    strcat(namehead, ":");

    int len = 0;
    while (1)
    {
        // 清空recvbuf
        bzero(recvbuf, sizeof(recvbuf));
        len = recv(client_id, recvbuf, sizeof(recvbuf), 0); // 接收数据到buf
        if (len <= 0)
        {
            // 群发
            int i;
            for (i = 0; i < 20; i++) // 找到退出的用户，清除数据
            {
                if (strcmp(client_ids[i].name, name) == 0)
                {
                    client_ids[i].cid = 0;
                    bzero(client_ids[i].name, 16);
                    break;
                }
            }
            bzero(hint, sizeof(hint));
            strcpy(hint, name);
            strcat(hint, "退出了聊天室,");
            strcat(hint, "当前在线用户：");
            int n;
            for (n = 0; n < 20; n++)
            {
                if (client_ids[n].name != NULL)
                {
                    strcat(hint, client_ids[n].name); // 添加名字
                    strcat(hint, " ");
                }
            }
            strcat(hint, "\n");
            mass_send(hint);
            printf("%s退出了聊天室\n", name);
            number--;
            printf("当前在线人数:%d\n", number);

            sleep(1);
            close(client_id);
            break;
        }
        if (strncmp(recvbuf, "@", 1) == 0)
        {
            flg = 1;
        }
        /***********   私发     **********/
        if (flg == 1)
        {
            char buf1[16] = "";  //@
            char buf2[16] = "";  // 私聊的名字
            char buf3[256] = ""; // 私聊的信息
            int ret = sscanf(recvbuf, "%s %s %s", buf1, buf2, buf3);
            if (ret != 3)
            {
                char error[256] = "@ 名字 要发送的消息\n";
                send(client_id, error, strlen(error), 0);
            }
            else
            {
                printf("%s私聊\n", name);
                memset(sendbuf, 0, 256);
                strcpy(sendbuf, name);
                ;                                 // 装入私聊发起者名字
                strcat(sendbuf, "悄悄的对你说:"); // 装入
                strcat(sendbuf, buf3);            // 包装好聊天信息
                strcat(hint, "\n");
                int i;
                for (i = 0; i < 20; i++)
                {
                    if (strcmp(client_ids[i].name, buf2) == 0)
                    {
                        send(client_ids[i].cid, sendbuf, strlen(sendbuf), 0); // 发送包装好的的信息
                        memset(sendbuf, 0, 256);
                        strcpy(sendbuf, "你悄悄的对");
                        strcat(sendbuf, client_ids[i].name);
                        strcat(sendbuf, "说:"); // 装入
                        strcat(sendbuf, buf3);  // 包装好聊天信息
                        strcat(hint, "\n");
                        send(client_id, sendbuf, strlen(sendbuf), 0);
                        break;
                    }
                }
                flg = 0;
            }

            // printf("1.string=%s\n", recvbuf);
            // printf("1.ret=%d, buf1=%s, buf2=%s,buf3=%s\n", ret, buf1, buf2,buf3);
        }

        /***********   群发     **********/
        else
        {
            if (strncasecmp(recvbuf, "exit", 4) == 0) // 检测到退出，关闭套接字
            {
                printf("[%s]退出了聊天室..\n", name);
                number--;
                int i;
                for (i = 0; i < 20; i++) // 找到退出的用户，清除数据
                {
                    if (strcmp(client_ids[i].name, name) == 0)
                    {
                        client_ids[i].cid = 0;
                        bzero(client_ids[i].name, 16);
                        break;
                    }
                }
                bzero(hint, sizeof(hint));
                strcpy(hint, name);
                strcat(hint, "退出了聊天室,");
                strcat(hint, "当前在线用户：");
                int n;
                for (n = 0; n < 20; n++)
                {
                    if (client_ids[n].name != NULL)
                    {
                        strcat(hint, client_ids[n].name); // 添加名字
                        strcat(hint, " ");
                    }
                }
                strcat(hint, "\n");
                mass_send(hint);
                printf("当前在线人数:%d\n", number);
                close(client_id);
                break;
            }

            memset(sendbuf, 0, 256);
            strcat(sendbuf, namehead); // 装入名字
            strcat(sendbuf, recvbuf);  // 包装好聊天信息
            mass_send(sendbuf);        // 群发
            printf("%s\n", sendbuf);
        }
    }
}

int main(int argc, char **argv)
{
    system("clear");
    if (argc < 3)
    {
        perror("使用: ./run + 自己IP地址 + 自己端口号\n");
        return -1;
    }
    int ret = 0;
    /****  1创建套接字 ****/
    int tcp_server = socket(AF_INET, SOCK_STREAM, 0);

    /***** 2绑定自己ip和端口   *****/
    struct sockaddr_in IPV4;
    IPV4.sin_family = AF_INET;
    IPV4.sin_port = htons(atoi(argv[2]));
    IPV4.sin_addr.s_addr = inet_addr(argv[1]);

    ret = bind(tcp_server, (struct sockaddr *)&IPV4, sizeof(IPV4));
    if (ret < 0)
    {
        perror("绑定失败..\n");
        return -1;
    }

    /******* 3监听  ********/
    listen(tcp_server, 10);
    system("clear");
    // printf("\n");
    // printf("\n");
    // printf("\t ------------------------uzoo云聊服务端----------------------\n");
    // printf("\t                   @@@@@@@@@@@@@@@@@@@@@@@@@@                \n");
    // printf("\t                 //                          \\\\            \n");
    // printf("\t            @@@---     1.   管理员登录        ---@@@          \n");
    // printf("\t          @@@---                                ---@@@        \n");
    // printf("\t        @@@---         2.    修改密码              ---@@@      \n");
    // printf("\t          @@@---                                ---@@@         \n");
    // printf("\t            @@@---     3.  退出登录界面       ---@@@            \n");
    // printf("\t                 \\\\                         //               \n");
    // printf("\t                   @@@@@@@@@@@@@@@@@@@@@@@@@@                  \n");
    //   usleep(2000000); // 暂停1秒
    printf("聊天室启动成功，等待用户连接..\n");

    /******* 4等待响应 *********/
    struct sockaddr_in IPV4_client; // 客户端的ip和端口
    socklen_t IPV4_len = sizeof(IPV4_client);

    pthread_t tid = 0;
    // int result = -1;
    while (1)
    {
        // printf("请输入你的选择：");
        // scanf("%d", &result);

        // switch (result)
        // {

        // case ADMIN:
        //     printf("1");

        //     break;

        // case RES:

        //     printf("2");
        //     break;

        // case EXIT:

        //     exit(0);
        //     break;

        // default:

        //     printf("输入错误，请重新输入！！！");
        //     break;
        // }
        int client_id = accept(tcp_server, (struct sockaddr *)&IPV4_client, &IPV4_len); // 每连接一个客户端，会有新的套接字，开新的线程处理该次连接
        /****** 5处理通讯 ******/
        if (client_id > 0)
        {
            int i;
            for (i = 0; i < 20; i++)
            {
                if (client_ids[i].cid == 0)
                {
                    client_ids[i].cid = client_id; // 把用户套接字存入数组，方便管理
                    printf("[%s:%d]连接到服务器..\n", inet_ntoa(IPV4_client.sin_addr), ntohs(IPV4_client.sin_port));

                    break;
                }
            }
            /*****      多线程处理    *******/
            pthread_create(&tid, NULL, pthread_func, &client_id);
            pthread_detach(tid);
            // /***** 查看数组中是否出现重复的 套接字ID *****/
            // printf("已经加入到聊天室的套接字:");
            // for(int i = 0; i < 20 ;i++)
            // {
            //     printf("%d,",client_ids[i].cid);
            // }
            // printf("\n");
        }
    }
    close(tcp_server);
    return 0;
}